﻿/* ***********************************************************************

Based on FlipImageSimple.as by Barbara Kaskosz (http://www.flashandmath.com/)

Custom by switcherdav

The FlipEffect class constructor takes 2 arguments, the 2 displayObjects 
for the front and the back side

The method flip( ) take one argument, the direction of the Flip

At the end of the movement, an FlipEvent.END_FLIP is dispatch

//TODO write exemple 

************************************************************************ */

package com.switcherdav {
	
	import flash.display.*;
	import flash.events.*;
	import flash.filters.DropShadowFilter;
	import flash.geom.*;
	
    public  class FlipEffect extends Sprite {
		
    		
    ////////////////
    // PROPERTIES
    ////////////////
    
    public var fLen:Number;
    
    private var do1:DisplayObject ;
    private var do2:DisplayObject ;
    
      
    private var bdFirst:BitmapData;
    private var bdSecond:BitmapData;
       
    private var picWidth:Number;
    private var picHeight:Number;
      
    private var isMoving:Boolean;
      
    private var spSide0:Sprite;
    private var spSide1:Sprite;
      
    private var firstSlices:Array; 
    private var secondSlices:Array;
    
    private var sliceWidth:Number;
    
    private var numSlices:Number;
    
    private var curTheta:Number;


    /*largeur et hauteurs des faces*/
    private var pic1W:Number ;
    private var pic1H:Number ;
    
    private var pic2W:Number ;
    private var pic2H:Number ;
    
    
    /*nombre de tranches des 2 faces*/
    private var numSlice1:Number ;
    private var numSlice2:Number ;
    
    /*indique la face affichée 0 ou 1*/
    private var currentSlide:uint ;

      
    ////////////////
    // METHODS
    ////////////////
      
    /**
    * constructeur
    * @param BitmapData front face
    * @param BitmapData back face
    */ 
    public function FlipEffect( do1:DisplayObject, do2:DisplayObject ):void
	{
	        
        fLen=400;
        
        isMoving=false;
        
        this.do1 = do1 ;
        this.do2 = do2 ;
    }
    
    private function initFlip():void
    {
       // creation des objets bitmapData pour le mouvement
        bdFirst = new BitmapData( do1.width, do1.height, true, 0 ) ;
        bdFirst.draw( do1 ) ;
        
        bdSecond = new BitmapData( do2.width, do2.height, true, 0 ) ;
        bdSecond.draw( do2 ) ;
        
        
        /*largeur et hauteur des faces*/
        pic1W = do1.width ;
        pic1H = do1.height ;
        
        pic2W = do2.width ;
        pic2H = do2.height ;


        /*création et placement des 2 faces*/
        
        spSide0 = new Sprite();
        this.addChild(spSide0);
        
        spSide0.x = pic1W / 2 + do1.x ;
        spSide0.y = pic1H / 2 + do1.y ;
        
        spSide1 = new Sprite();
        this.addChild(spSide1);

        spSide1.x = pic2W / 2 + do2.x ;
        spSide1.y = pic2H / 2 + do2.y ;

        /*ajout d'ombre portée*/
        var shadow:DropShadowFilter = new DropShadowFilter() ;
        shadow.color = 0x333333 ;
        
        spSide0.filters = [ shadow ];
        spSide1.filters = [ shadow ];
        
        /*tableaux qui contiennent les faces découpées en tranches pour la perspective*/
        firstSlices      = []; 
        secondSlices = [];
        
        /* largeur d'une tranche*/
        sliceWidth = 1;


        /*nombre de tranches des 2 faces*/
        numSlice1 = pic1W / sliceWidth ;
        numSlice2 = pic2W / sliceWidth ;


        curTheta=0;
        
        /* découpe les faces en tranches*/
        cutSlices();
        
        /*place les tranches*/
        renderView(curTheta);
        
        /*défini les écouteurs pour le flip*/
        setUpListeners();        
    }
	
	/**
	 * decoupe les faces en tranches et les places dans un sprite
	 */ 
    private function cutSlices():void
     {
    	
    	var i:uint ;

        for( i=0; i< numSlice1; i++ )
        {
            firstSlices[i] = new Bitmap( new BitmapData( sliceWidth+1, pic1H, true, 0 ) );            
            firstSlices[i].bitmapData.copyPixels( bdFirst,new Rectangle( i*sliceWidth,0,sliceWidth+1,pic1H ),new Point( 0,0 ) ) ;

            spSide0.addChild( firstSlices[i] );
        }


        for( i=0 ; i < numSlice2 ; i++ )
        {
            secondSlices[i]=new Bitmap(new BitmapData(sliceWidth+1,pic2H, true, 0 ) ) ;
            secondSlices[i].bitmapData.copyPixels( bdSecond,new Rectangle( i*sliceWidth,0,sliceWidth+1,pic2H ),new Point(0,0));

            spSide1.addChild( secondSlices[i] );            
        }
   }

    /**
    * place les tranches dans les sprites en fonction de la rotation
    * permet d'avoir la perspective et la rotation sur axe Z
    */ 
    private function renderView(t:Number):void
    {           
        var j:int;
        
        var curv0:Array=[];
        
        var curv1:Array=[];
        
        var curv2:Array=[];
        
        var curv3:Array=[];
        
        var curNormal:Number;
        
        var factor1:Number;
        
        var factor2:Number;
        
        var curTransMatrix:Matrix;
        
        t=t*Math.PI/180;
        
        curNormal = Math.cos(t);
        
        /* masque ou affiche les tranches des faces*/
        if( curNormal >= 0 )
        {
            /*affiche la face 1 et masque la face 2*/
            spSide0.visible = true ;
            spSide1.visible = false ;           
            
        } 
        else
        {
            /*masque la face 1 et affiche la face 2*/
            spSide0.visible = false ;
            spSide1.visible = true ;
        }
	
	
	    /*rotation de la face 1*/
        for( j=0; j<numSlice1; j++ )
        {
            factor1=fLen/( fLen-Math.sin(t)*(-pic1W/2+j*sliceWidth ) ) ;
            		
            factor2=fLen/( fLen-Math.sin(t)*(-pic1W/2+(j+1)*sliceWidth ) ) ;
            		
            curv0=[factor1*(-pic1W/2+j*sliceWidth)*Math.cos(t),-factor1*pic1H/2];
            		
            curv1=[factor2*(-pic1W/2+(j+1)*sliceWidth)*Math.cos(t),-factor2*pic1H/2];
            	
            curv2=[factor2*(-pic1W/2+(j+1)*sliceWidth)*Math.cos(t),factor2*pic1H/2];
            	
            curv3=[factor1*(-pic1W/2+j*sliceWidth)*Math.cos(t),factor1*pic1H/2];
            	
            curTransMatrix = calcMatrixForSides( curv0,curv1,curv2,curv3, pic1H );
            	
            firstSlices[j].transform.matrix=curTransMatrix;
        		
        }



 		
		/*rotation de la face 2*/	
		for(j=0;j<numSlice2;j++)
		{
			
			factor1 = fLen/(fLen-Math.sin(t)*(pic2W/2-j*sliceWidth));
			
			factor2 = fLen/(fLen-Math.sin(t)*(pic2W/2-(j+1)*sliceWidth));
		
		    curv0 = [factor1*(pic2W/2-j*sliceWidth) * Math.cos(t),-factor1*pic2H/2];
			
			curv1 = [factor2*(pic2W/2-(j+1)*sliceWidth) * Math.cos(t),-factor2*pic2H/2];
		
		    curv2 = [factor2*(pic2W/2-(j+1)*sliceWidth) * Math.cos(t),factor2*pic2H/2];
		
		    curv3 = [factor1*(pic2W/2-j*sliceWidth) * Math.cos(t),factor1*pic2H/2];
		
		    curTransMatrix = calcMatrixForSides( curv0,curv1,curv2,curv3, pic2H );
		
		    secondSlices[j].transform.matrix=curTransMatrix;
	   }
	
    }


    private function calcMatrixForSides(v0:Array,v1:Array,v2:Array,v3:Array, picH:Number):Matrix 
    {
	
	    var curMatrix:Matrix;
	
	    var transMatrix:Matrix;
	
	    var v:Array=findVecMinusVec(v1,v0);
	
	    var w:Array=findVecMinusVec(v3,v0);
	
	    curMatrix=new Matrix(v[0]/sliceWidth,v[1]/sliceWidth,w[0]/picH,w[1]/picH);
	
	    transMatrix=new Matrix(1,0,0,1,v0[0],v0[1]);
	
	    curMatrix.concat(transMatrix);
	
	    return curMatrix;
	
     }

     private function findVecMinusVec(v:Array,w:Array):Array 
     {	
	    return [v[0]-w[0],v[1]-w[1],v[2]-w[2]];
     }
	
	
	
	private function setUpListeners():void 
	{
		//spSide0.addEventListener(MouseEvent.CLICK,sideClicked);

        //spSide1.addEventListener(MouseEvent.CLICK,sideClicked);
		
		this.addEventListener(Event.ENTER_FRAME,onEnter);
	}
	
	
	private function sideClicked(e:MouseEvent):void 
	{
	
	   if(isMoving==false)
	   {
	       isMoving=true;
	    }
    }
	
	/**
	 * dés que le mouvement est défini sur true, on tourne
	 * une fois le mouvement teminé le mouvement devient false
	 */ 
	private function onEnter(e:Event): void 
	{
        if( isMoving )
        {
            curTheta+=36;
		
            curTheta=curTheta%360;
				
		    renderView(curTheta);
		
            if((curTheta%180)==0)
    		{
    		    isMoving = false;
    		    
    		    trace( currentSlide ) ;
    		    
    		   do2.visible       = true ;
    		   spSide1.visible = false ;
    		    	
    		    if( currentSlide == 0)
    		    {
    		        currentSlide = 1 ;
    		    }
    		    else
    		    {
    		        currentSlide = 0 ;
    		    }
    		    
    		    dispatchEvent( new FlipEvent( FlipEvent.END_FLIP, currentSlide ) ) ;
    		}
        }
    }
    
    /**
    * declenche le flip
    */ 
    public function flip():void
    {
       isMoving = true ; 
    }
    
    public function flipMe():void
    {
        // si la premier face est visible, on la masque
        initFlip() ;
        do1.visible = false ;
        
        isMoving = true ;
    }


   }

}